#include "commandprocessor.h"

#include <QString>
#include <QTextStream>
#include <QColor>
#include <QMessageBox>
#include "ParsingException.h"

#include <QDebug>

CommandProcessor::CommandProcessor(const LanguageToken &lang, QObject *parent ) :
    QObject(parent), _lang(lang)
{

}

CommandProcessor::~CommandProcessor() {

}

void CommandProcessor::processText(const QString &text)
{
    QTextStream ts(const_cast<QString *>(&text), QIODevice::ReadOnly);

    int lineNumber = 0;

    QString line;
    while( !ts.atEnd() ) {
        ++lineNumber;

        line = ts.readLine().trimmed();

        if( line.isEmpty() ) continue;

        if( line.startsWith("//") || line.startsWith("#") || line.startsWith(";") ) continue;

        QStringList tokens = line.split(" ", QString::SkipEmptyParts);
        if( tokens.size() < 1 ) return;

        CommandList cmdList;

        int size = tokens.size();
        int offset = 0;
        try {
            while( offset < size ) {
                offset = processCommand(tokens, offset, cmdList);
                if( offset <= 0 ) {
                    break;
                }
            }
        } catch(ParsingException &pe) {
            QMessageBox::critical(nullptr, "Erro lendo comandos", "<font color='red'>" + pe.message() + ". linha " +
                                  QString::number(lineNumber) + ". </font><br/>" + line);
            return;
        }

        for(auto &item : cmdList) {
            executeCommand(item);
        }
    }
}

int CommandProcessor::processCommand(const QStringList &tokens, int start, CommandList &cmdList)
{
    const QString &cmd = tokens[start];
    QString val;
    if( tokens.size() > start+1 ) val = tokens[start+1];

    int cmdSize = 0;

    if( _lang.paraFrente().compare(cmd, Qt::CaseInsensitive) == 0 ) {
        cmdSize = 2;
    } else if( _lang.paraTras().compare(cmd, Qt::CaseInsensitive) == 0 ) {
        cmdSize = 2;
    } else if( _lang.girarDireita().compare(cmd, Qt::CaseInsensitive) == 0 ) {
        cmdSize = 2;
    } else if( _lang.girarEsquerda().compare(cmd, Qt::CaseInsensitive) == 0 ) {
        cmdSize = 2;
    } else if( _lang.pular().compare(cmd, Qt::CaseInsensitive) == 0 ) {
        cmdSize = 2;
    } else if( _lang.forca().compare(cmd, Qt::CaseInsensitive) == 0 ) {
        cmdSize = 2;
    } else if( _lang.limpar().compare(cmd, Qt::CaseInsensitive) == 0 ) {
        cmdSize = 1;
    } else if( _lang.mudarCor().compare(cmd, Qt::CaseInsensitive) == 0 ) {
        cmdSize = 2;
    } else {
        cmdSize = 0;
    }

    QStringList cmds;
    for( int i=0; i < cmdSize; i++ ) {
        if( start+i < tokens.size() ) {
            QString token = tokens[start+i];
            cmds.push_back(token);
        } else {
            throw ParsingException("Comando invalido");
        }

    }
    cmdList.push_back( cmds );

    return start + cmdSize;
}

#define IV ((tokens.size() > 1)?tokens[1].toInt():0)
#define SV ((tokens.size() > 1)?tokens[1]:"")
#define SCOR(x, r, g, b) if( sVal.compare(x, Qt::CaseInsensitive) == 0 ) val.setRgb(r, g, b)

void CommandProcessor::executeCommand(const QStringList &tokens)
{
    if( tokens.size() == 0 )
        return;

    const QString &cmd = tokens[0];
    //int val = 0;
    //if( tokens.size() > 1 ) val = tokens[1].toInt();

    if( _lang.paraFrente().compare(cmd, Qt::CaseInsensitive) == 0 ) {
        emit paraFrente(IV);

    } else if( _lang.paraTras().compare(cmd, Qt::CaseInsensitive) == 0 ) {
        emit paraTras(IV);

    } else if( _lang.girarDireita().compare(cmd, Qt::CaseInsensitive) == 0 ) {
        emit girarDireita(IV);

    } else if( _lang.girarEsquerda().compare(cmd, Qt::CaseInsensitive) == 0 ) {
        emit girarEsquerda(IV);

    } else if( _lang.pular().compare(cmd, Qt::CaseInsensitive) == 0 ) {
        emit pular(IV);

    } else if( _lang.forca().compare(cmd, Qt::CaseInsensitive) == 0 ) {
        emit forca(IV);

    } else if( _lang.limpar().compare(cmd, Qt::CaseInsensitive) == 0 ) {
        emit limpar();

    } else if( _lang.mudarCor().compare(cmd, Qt::CaseInsensitive) == 0 ) {
        QString sVal = SV;
        QColor val;

        if( sVal.indexOf(',') > 0 ) {
            QStringList list = sVal.split(",");
            if( list.size() != 3 )
                emit erro("Cor inválida: " + sVal);
            int r = list[0].toInt();
            int g = list[1].toInt();
            int b = list[2].toInt();
            val.setRgb(r, g, b);
        } else {

            SCOR("VERDE", 0, 255, 0);
            SCOR("AZUL", 0, 0, 255);
            SCOR("VERMELHO", 255, 0, 0);
            SCOR("AMARELO", 255, 255, 0);
            SCOR("ROXO", 160, 32, 240);
            SCOR("ROSA", 255, 181, 197);
            SCOR("PRETO", 0, 0, 0);
            SCOR("BRANCO", 255, 255, 255);
            SCOR("LARANJA", 255, 165, 0);
            SCOR("MARROM", 255, 64, 64);
            SCOR("CINZA", 128, 128, 128);
            SCOR("MAGENTA", 255, 0, 255);
        }

        //COR
        emit mudarCor(val);

    } else {
        emit erro("Comando inválido: " + cmd);
    }

}
